{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 37,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'radius': 2.5}\n"
     ]
    }
   ],
   "source": [
    "class Circle(object):\n",
    "    def __init__(self,radius):\n",
    "        self.radius = radius\n",
    "    \n",
    "c = Circle(2.5)\n",
    "print(c.__dict__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'radius': 2.5}\n"
     ]
    },
    {
     "ename": "AttributeError",
     "evalue": "'Circle' object has no attribute '__method__'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m                            Traceback (most recent call last)",
      "\u001b[0;32m<ipython-input-6-14458faf2f0e>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0mcircle\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mCircle\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2.5\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcircle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__dict__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcircle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0m__method__\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
      "\u001b[0;31mAttributeError\u001b[0m: 'Circle' object has no attribute '__method__'"
     ]
    }
   ],
   "source": [
    "class Circle(object):\n",
    "    def __init__(self,radius):\n",
    "        self.radius = radius\n",
    "    def area(self):\n",
    "        print(\"calculate area\")\n",
    "        return 3.14 * self.radius * 2\n",
    "circle = Circle(4)\n",
    "\n",
    "print(circle.__dict__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'radius': 4}\n",
      "calculate area\n",
      "25.12\n",
      "calculate area\n",
      "25.12\n",
      "{'radius': 4}\n"
     ]
    }
   ],
   "source": [
    "# property可以将属性的访问转变成方法的调用\n",
    "# area虽然是定义成一个方法的形式，但是加上@property后，可以直接执行c.area，当成属性访问。\n",
    "# 但是没有真正意义上把area变成类的属性\n",
    "# 现在问题来了，每次调用c.area，都会计算一次，太浪费cpu了，怎样才能只计算一次呢?这就是lazy property。\n",
    "class Circle(object):\n",
    "    def __init__(self,radius):\n",
    "        self.radius = radius\n",
    "    @property\n",
    "    def area(self):\n",
    "        print(\"calculate area\")\n",
    "        return 3.14 * self.radius * 2\n",
    "    \n",
    "c = Circle(4) \n",
    "print(c.__dict__)\n",
    "print(c.area)\n",
    "print(c.area)\n",
    "print(c.__dict__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "before calculate area\n",
      "{'radius': 4}\n",
      "calculate area\n",
      "50.24\n",
      "calculate area\n",
      "50.24\n",
      "after calculate area\n",
      "{'radius': 4, 'lazyarea': 50.24}\n",
      "{'radius': 5, 'lazyarea': 50.24}\n",
      "calculate area\n",
      "78.5\n"
     ]
    }
   ],
   "source": [
    "class lazy(object):\n",
    "    def __init__(self, func):\n",
    "        self.func = func\n",
    "\n",
    "    def __get__(self, instance, cls):\n",
    "        val = self.func(instance)\n",
    "        setattr(instance, 'lazy'+self.func.__name__, val)\n",
    "        return val\n",
    "\n",
    "class Circle(object): \n",
    "  def __init__(self, radius): \n",
    "    self.radius = radius \n",
    "  \n",
    "  @lazy\n",
    "  def area(self): \n",
    "    print(\"calculate area\")\n",
    "    return 3.14 * self.radius ** 2\n",
    "\n",
    "c = Circle(4) \n",
    "print('before calculate area')\n",
    "print(c.__dict__)\n",
    "print(c.area)\n",
    "print(c.area)\n",
    "print('after calculate area')\n",
    "print(c.__dict__)\n",
    "c.radius = 5\n",
    "print(c.__dict__)\n",
    "print(c.area)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "before calculate area\n",
      "{'radius': 4}\n",
      "50.24\n",
      "50.24\n",
      "after calculate area\n",
      "{'radius': 4, '_lazy_area': 50.24}\n",
      "{'radius': 5, '_lazy_area': 50.24}\n",
      "50.24\n"
     ]
    }
   ],
   "source": [
    "def lazy_property(func):\n",
    "    attr_name = \"_lazy_\" + func.__name__\n",
    "\n",
    "    @property\n",
    "    def _lazy_property(self):\n",
    "        if not hasattr(self, attr_name):\n",
    "            setattr(self, attr_name, func(self))\n",
    "        return getattr(self, attr_name)\n",
    "\n",
    "    return _lazy_property\n",
    "\n",
    "class Circle(object): \n",
    "  def __init__(self, radius): \n",
    "    self.radius = radius \n",
    "  \n",
    "  @lazy_property\n",
    "  def area(self): \n",
    "    return 3.14 * self.radius ** 2\n",
    "\n",
    "c = Circle(4) \n",
    "print('before calculate area')\n",
    "print(c.__dict__)\n",
    "print(c.area)\n",
    "print(c.area)\n",
    "print('after calculate area')\n",
    "print(c.__dict__)\n",
    "c.radius = 5\n",
    "print(c.__dict__)\n",
    "print(c.area)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1 4 9\n"
     ]
    }
   ],
   "source": [
    "def t(n):\n",
    "    def g(j):\n",
    "        def f():\n",
    "            return j * j\n",
    "        return f\n",
    "        \n",
    "    func = []\n",
    "    for i in range(1,n+1):\n",
    "        func.append(g(i))\n",
    "    return func\n",
    "f1 ,f2,f3 = t(3)\n",
    "print(f1(),f2(),f3())"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "call now()\n",
      "2018-12-18\n",
      "wrapper\n"
     ]
    }
   ],
   "source": [
    "import functools\n",
    "\n",
    "def log(func):\n",
    "    @functools.wraps(func)\n",
    "    def wrapper(*args,**kw):\n",
    "        print('call %s()' % (func.__name__))\n",
    "        return func(*args,**kw)\n",
    "    return wrapper\n",
    "\n",
    "@log\n",
    "def now():\n",
    "    print('2018-12-18')\n",
    "\n",
    "now()\n",
    "print(now.__name__)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.1"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
